home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 2
/
Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso
/
Aminet
/
misc
/
amag
/
sh9301c.lha
/
Differenzieren(S.91)
/
How-2-Derive.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-10-24
|
32KB
|
1,225 lines
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <intuition/intuition.h>
#include <proto/intuition.h>
#include <proto/exec.h>
#include <proto/graphics.h>
struct bits {unsigned K:1,Neg:1,Konst:1;};
typedef union {unsigned mask;struct bits is;} FLAGS;
typedef enum {OP_OPEN=-2,OP_CLOSE,OP_NONE=0,
OP_ADD,OP_SUB,OP_MUL,OP_DIV,OP_NEG,OP_POT,OP_FUNC1,OP_USERF=100} OP;
typedef enum {PRI_NONE,PRI_ADDSUB,PRI_MULDIV,PRI_NEG,PRI_POT,PRI_FUNC} PRI;
struct Knoten {
FLAGS flags; OP op; PRI pri;
short primes;
struct Knoten *links,*rechts;
double konst;
short len; char *term;
} *Root;
BOOL verwende(OP);
struct Knoten *Verschmelze(struct Knoten *,struct Knoten *),
*Vereinfache(struct Knoten *,struct Knoten *,PRI,struct Knoten *,struct Knoten *,int),
*Verkette(struct Knoten *,OP,struct Knoten *);
char *Baum_String(struct Knoten *,char *),
*Baum_zu_String(struct Knoten *,char *);
struct Knoten *Differenziere(struct Knoten *,struct list *),*Regeln(void);
char Puffer1[1024],Puffer2[1024],Puffer3[1024],Puffer4[1024];
char *cp,*term,*Beginn;
char *Funktionen[]={"ln","sinh","cosh","sin","cos",
"tanh","coth","tan","cot","log","arcsin","arccos",
"arctan","arccot","sqrt","arsinh","arcosh",
"artanh","arcoth","exp",NULL};
char *FunkMsg[]={"z'/z","z'*cosh z","z'*sinh z","z'*cos z","z'*(-sin z)",
"z'/(cosh z)^2","-z'/(sinh z)^2","z'/(cos z)^2","-z'/(sin z)^2",
"z'/z*log e","z'/sqrt(1-z^2)","-z'/sqrt(1-z^2)",
"z'/(1+z^2)","-z'/(1+z^2)","z'/(2*sqrt(z))","z'/sqrt(1+z^2)",
"z'/sqrt(z^2-1)","z'/(1-z^2)","z'/(1-z^2)","z'*exp(z)"};
OP op_stack[1024];
int op_sp,kn_sp;
struct Knoten *kn_stack[1024];
PRI oppri[]={PRI_NONE,PRI_ADDSUB,PRI_ADDSUB,
PRI_MULDIV,PRI_MULDIV,PRI_NEG,PRI_POT};
PRI Pri(OP op) {return op<OP_FUNC1?oppri[op]:PRI_FUNC;}
char chop[]={"+-*/_^"};
#define opnr(c) ((OP)(strchr(chop,c)-chop)+OP_ADD)
#define Op(op) ((op)<OP_FUNC1?&chop[(op)-1]:Funktionen[(op)-OP_FUNC1])
#define kommOp(op) ((op)==OP_MUL || (op)==OP_DIV ? OP_MUL : OP_ADD)
#define nkommOp(op) ((op)==OP_MUL || (op)==OP_DIV ? OP_DIV : OP_SUB)
#define StdKonst(pri) ((pri)==PRI_ADDSUB?0.:1.)
#define inv_konst(d,pri) ((d)?(pri)==PRI_ADDSUB?-(d):1./(d):(errno=EDOM,0.))
#define X(k) ((k)->op==OP_NONE && (k)->len==1 && (k)->term[0]=='x')
#define C(k) ((k)->op==OP_NONE && (k)->flags.is.Konst)
void inv_K(struct Knoten *k, PRI pri)
{
struct Knoten *n=k->links;
k->links=k->rechts; k->rechts=n;
k->konst=inv_konst(k->konst,pri);
}
void Rechne(struct Knoten *l,OP op,struct Knoten *r)
{
switch(op) {
case OP_ADD: l->konst+=r->konst; break;
case OP_SUB: l->konst-=r->konst; break;
case OP_MUL: l->konst*=r->konst; break;
case OP_DIV: if(r->konst) l->konst/=r->konst;
else errno=EDOM; break;
}
}
void Negiere(struct Knoten *k)
{
struct Knoten *n;
if(k->pri==PRI_ADDSUB) {
k->konst=-k->konst; n=k->links;
k->links=k->rechts; k->rechts=n;
}
else if((k->pri==PRI_MULDIV || k->op==OP_NONE) && k->flags.is.Konst)
k->konst=-k->konst;
else k->flags.is.Neg=!k->flags.is.Neg;
}
BOOL Term_korrekt(char *term)
{
char c,*lastop=NULL,*p=term;
int kl=0;
cp=term-1;
while((c=*++cp)!=0) if(!isspace(c)) {
if(strchr("()+-*/^",c)) {
if(c=='(') kl++;
else if(c==')') {
if(--kl<0 || lastop+1==cp || cp[-1]=='(') return FALSE;
} else {
if(lastop+1==cp || c!='-' && cp[-1]=='(') return FALSE;
lastop=cp;
}
}
else if(!isalnum(c) && !strchr(".'",c)) return FALSE;
*p++=c;
}
*p=0; return (BOOL)(kl==0);
}
struct Knoten *Neuer_Operator(OP op)
{
struct Knoten *k;
if(!(k=malloc(sizeof(struct Knoten)))) {
fprintf(stderr,"Speicher voll!\n");
exit(10);
}
k->links=k->rechts=NULL;
k->flags.mask=0; k->primes=0;
k->op=op; k->pri=Pri(op);
if(op<OP_USERF) {
k->term=Op(op);
k->len=op>=OP_FUNC1?strlen(k->term):1;
}
else {int i;
k->op=OP_USERF;
k->term=term+op-OP_USERF;
if(!strncmp(k->term,"log",3)) k->op=OP_FUNC1+9;
for(i=0;isalnum(k->term[i]);i++);
k->len=i;
while(k->term[i++]=='\'') k->primes++;
}
k->konst=0.; return k;
}
struct Knoten *NeuerK(OP op)
{
struct Knoten *k=Neuer_Operator(nkommOp(op));
k->flags.is.K=k->flags.is.Konst=1;
k->konst=StdKonst(k->pri);
return k;
}
struct Knoten *Neue_Konst(double d)
{
struct Knoten *k=Neuer_Operator(OP_NONE);
k->flags.is.Konst=1;
k->konst=d; return k;
}
struct Knoten *Neues_Blatt(char *cp,char **x)
{
struct Knoten *k=Neuer_Operator(OP_NONE);
char *s;
if(isdigit(*cp)) {
sscanf(cp,"%lf",&k->konst);
if(!(s=strpbrk(cp,"()+-*^/"))) s=strchr(cp,0);
k->flags.is.Konst=1;
}
else {
k->konst=0.; s=cp;
while(isalnum(*++s));
}
k->term=cp; k->len=s-cp;
*x=s; return k;
}
struct Knoten *Baum_aufbauen(char *cp)
{
int i,l; char c;
PRI p,p2; OP op,op2;
term=cp;
while((c=*cp)!=0) {
if(c=='(') op_stack[op_sp++]=OP_OPEN;
else if(isalnum(c)) {
if(isalpha(c)) {
for(i=0;Funktionen[i];i++)
if(!strncmp(Funktionen[i],cp,l=strlen(Funktionen[i]))) {
op=OP_FUNC1+i;
if(op==OP_FUNC1+9) {
op=(cp-term)+OP_USERF;
while(isalnum(cp[3])) cp++;
}
function: p=PRI_FUNC; cp+=l-1;
goto operator;
}
for(l=0;isalnum(cp[l])||cp[l]=='\'';l++);
if(cp[l]=='(') {
op=(cp-term)+OP_USERF;
goto function;
}
}
kn_stack[kn_sp++]=Neues_Blatt(cp,&cp);
cp--;
}
else if(c==')')
for(;;) {
if(!op_sp) goto error;
op=op_stack[--op_sp];
if(op!=OP_OPEN) {if(!verwende(op)) goto error;}
else break;
}
else if(strchr(chop,c)) {
op=opnr(c); p=Pri(op);
if(op==OP_SUB && (cp==term || cp[-1]=='(')) {
op=OP_NEG;
p=PRI_NEG;
}
operator:
while(op_sp) {
op2=op_stack[op_sp-1];
p2=Pri(op2);
if(op2==OP_OPEN || p2<p || (p==PRI_FUNC || p==PRI_POT) && p2==p) break;
--op_sp;
if(!verwende(op2)) goto error;
}
op_stack[op_sp++]=op;
}
else goto error;
cp++;
}
while(op_sp) {
op2=op_stack[--op_sp];
if(op2==OP_CLOSE) goto error;
if(!verwende(op2)) goto error;
}
if(kn_sp!=1) goto error;
return kn_stack[--kn_sp];
error:
while(kn_sp) free(kn_stack[--kn_sp]);
return NULL;
}
void Baum_abbauen(struct Knoten *k)
{
if(k) {
if(k->links) Baum_abbauen(k->links);
if(k->rechts) Baum_abbauen(k->rechts);
free(k);
}
}
struct Knoten *Sinnlos(struct Knoten *k)
{
if(!k->links && !k->rechts) {
k->flags.is.K=0;
k->op=OP_NONE; k->pri=PRI_NONE;
}
if(k->pri==PRI_MULDIV && k->flags.is.Konst && k->konst==0.) {
Baum_abbauen(k);
return Neue_Konst(0.);
}
if(k->op==OP_POT && k->rechts->flags.is.Konst && k->rechts->op==OP_NONE) {
if(k->rechts->konst==0.) {
Baum_abbauen(k);
return Neue_Konst(1.);
}
if(k->rechts->konst==1.) {
struct Knoten *n=k->links;
k->links=NULL;
Baum_abbauen(k);
return Sinnlos(n);
}
}
if(k->flags.is.Konst && k->links && !k->rechts && !k->links->links)
if(k->konst==StdKonst(k->pri) || k->pri==PRI_MULDIV && k->konst==-1.) {
struct Knoten *n=k->links->rechts;
k->links->rechts=NULL;
if(k->konst==-1.) Negiere(n);
Baum_abbauen(k);
return Sinnlos(n);
}
return k;
}
struct Knoten *verkette_Pot(struct Knoten *l,struct Knoten *r)
{
struct Knoten *k;
if(r->op==OP_NONE && r->flags.is.Konst &&
l->op==OP_NONE && l->flags.is.Konst) {
l->konst=pow(l->konst,r->konst);
Baum_abbauen(r); return l;
}
k=Neuer_Operator(OP_POT);
k->links=l; k->rechts=r;
return Sinnlos(k);
}
BOOL verwende(OP op)
{
struct Knoten *l,*r,*k;
#define kn_pop(w) {if(kn_sp<=0) return FALSE;(w)=kn_stack[--kn_sp];}
kn_pop(r);
switch(Pri(op)) {
case PRI_POT:
kn_pop(l);
k=verkette_Pot(l,r); break;
case PRI_ADDSUB:
case PRI_MULDIV:
kn_pop(l);
k=Verkette(l,op,r); break;
case PRI_NEG: Negiere(k=r);break;
case PRI_FUNC:
k=Neuer_Operator(op);
k->rechts=r; break;
}
kn_stack[kn_sp++]=k; return TRUE;
}
struct Knoten *Verkette(struct Knoten *l,OP op,struct Knoten *r)
{
OP kop=kommOp(op),nkop=nkommOp(op);
PRI pri=Pri(op);
struct Knoten *k,*o;
BOOL l_homogen=l->flags.is.Konst && l->op==OP_NONE || l->pri==pri;
BOOL r_homogen=r->flags.is.Konst && r->op==OP_NONE || r->pri==pri;
if(op==OP_POT) return verkette_Pot(l,r);
if(!r_homogen) {
o=Neuer_Operator(op);
if(l_homogen) {
if(l->op==OP_NONE) {
k=NeuerK(op);
k->konst=l->konst;
Baum_abbauen(l);
}
else k=l;
o->rechts=r;
k=Verschmelze(k,o);
}
else {
struct Knoten *n=Neuer_Operator(kop);
n->rechts=l; o->rechts=r;
k=Verschmelze(NeuerK(op),n);
k=Verschmelze(k,o);
}
}
else {
if(!l_homogen) {
o=Neuer_Operator(op);
if(r->op==OP_NONE) {
k=NeuerK(op);
k->konst=op==kop?r->konst:inv_konst(r->konst,pri);
o->rechts=l; o->op=kop;
k=Verschmelze(k,o);
Baum_abbauen(r);
}
else {
k=r;
if(op==nkop) {
inv_K(k,pri);
o->op=kop;
}
o->rechts=l;
k=Verschmelze(k,o);
}
}
else {
if(l->op==OP_NONE) {
if(r->op==OP_NONE) {
Rechne(k=l,op,r);
Baum_abbauen(r);
}
else {
k=r;
if(op==nkop) inv_K(k,pri);
Rechne(k,kop,l);
Baum_abbauen(l);
}
}
else {
if(r->op==OP_NONE) {
Rechne(k=l,op,r);
Baum_abbauen(r);
}
else {
Rechne(l,op,r);
o=r->links;
while(o) {
k=o->links;
o->links=NULL;
if(op==nkop) o->op=nkop;
l=Verschmelze(l,o);
o=k;
}
o=r->rechts;
while(o) {
k=o->links;
o->links=NULL;
if(op==kop) o->op=nkop;
l=Verschmelze(l,o);
o=k;
}
r->links=r->rechts=NULL;
Baum_abbauen(r); k=l;
}
}
}
}
return Sinnlos(k);
}
struct Knoten *BaumKopie(struct Knoten *k)
{
struct Knoten *n=NULL;
if(k) {
n=Neuer_Operator(OP_NONE);
*n=*k;
n->links=BaumKopie(k->links);
n->rechts=BaumKopie(k->rechts);
}
return n;
}
TreeCmp(const void *l,const void *r)
{
Baum_zu_String((*(struct Knoten *const*)l)->rechts,Puffer3);
Baum_zu_String((*(struct Knoten *const*)r)->rechts,Puffer4);
return strcmp(Puffer3,Puffer4);
}
struct Knoten *sortK(struct Knoten *k)
{
void SortBaum(struct Knoten *);
struct Knoten *n,**nl;
int i,j;
for(i=0,n=k;n;i++,n=n->links) SortBaum(n->rechts);
if(i>1) {
if(!(nl=(struct Knoten **)malloc(sizeof(n)*i))) {
fprintf(stderr,"Speicher voll!\n");
exit(10);
}
for(n=k,j=0;n;n=n->links,j++) nl[j]=n;
qsort((void*)nl,i,sizeof(n),TreeCmp);
for(k=n=*nl,j=1;j<i;n=n->links,j++) n->links=nl[j];
n->links=NULL; free(nl);
}
return k;
}
void SortBaum(struct Knoten *k)
{
if(!k) return;
if(k->flags.is.K) {
k->links=sortK(k->links);
k->rechts=sortK(k->rechts);
} else {
SortBaum(k->links); SortBaum(k->rechts);
}
}
void Wegen_NegPot(struct Knoten *o,struct Knoten *k)
{
struct Knoten *n=o->rechts;
if(n->op==OP_POT) {
do n=n->rechts;
while(n->op==OP_POT);
if(n->op==OP_NONE && n->flags.is.Konst && n->konst<0.) {
o->op=o->op==OP_MUL?OP_DIV:OP_MUL;
n->konst=-n->konst;
if(n->konst==1.)
for(n=o;n->rechts && n->rechts->op==OP_POT;n=n->rechts)
n->rechts=Sinnlos(n->rechts);
}
}
else if(n->flags.is.Neg) {
n->flags.is.Neg=!n->flags.is.Neg;
Negiere(k);
}
}
void Wegen_NegVorz(struct Knoten *o)
{
if(o->rechts->flags.is.Neg) {
o->rechts->flags.is.Neg=0;
o->op=o->op==OP_ADD?OP_SUB:OP_ADD;
}
else if(o->rechts->flags.is.Konst && (o->rechts->op==OP_NONE ||
o->rechts->pri==PRI_MULDIV) && o->rechts->konst<0.) {
o->rechts->konst=-o->rechts->konst;
o->op=o->op==OP_ADD?OP_SUB:OP_ADD;
}
}
struct Knoten *Ignoriere(struct Knoten *k,PRI pri)
{
if(pri==PRI_ADDSUB && k->pri==PRI_MULDIV && !k->rechts && k->links &&
!k->links->links && k->links->rechts)
return k->links->rechts;
else if(pri==PRI_MULDIV && k->op==OP_POT && k->rechts->op==OP_NONE &&
k->rechts->flags.is.Konst)
return k->links;
return k;
}
char *SortB_String(struct Knoten *k,char *s)
{
struct Knoten *cpy=BaumKopie(k);
SortBaum(cpy); s=Baum_zu_String(cpy,s);
Baum_abbauen(cpy); return s;
}
struct Knoten *Verschmelze(struct Knoten *k,struct Knoten *o)
{
OP kop;
struct Knoten *l,*r,*p1,*p2;
int v1=1,v2=1;
PRI pri=k->pri;
if(!o) return k;
kop=kommOp(o->op);
if(o->pri==PRI_MULDIV) Wegen_NegPot(o,k);
else Wegen_NegVorz(o);
SortB_String(Ignoriere(o->rechts,pri),Puffer1);
l=k->links; p1=NULL;
while(l) {
SortB_String(Ignoriere(l->rechts,pri),Puffer2);
v1=strcmp(Puffer2,Puffer1);
if(v1==0 || !l->links) break;
p1=l; l=l->links;
}
r=k->rechts; p2=NULL;
while(r) {
SortB_String(Ignoriere(r->rechts,pri),Puffer2);
v2=strcmp(Puffer2,Puffer1);
if(v2==0 || !r->links) break;
p2=r; r=r->links;
}
if(v1==0) k=Vereinfache(l,o,pri,k,p1,1);
else if(v2==0) k=Vereinfache(r,o,pri,k,p2,2);
else if(o->op==kop) {
if(!l) l=k;
o->links=l->links; l->links=o;
} else {
o->op=kop;
if(r) {
o->links=r->links; r->links=o;
} else {
o->links=k->rechts; k->rechts=o;
}
}
return k;
}
struct Knoten *Vereinfache(struct Knoten *o1,struct Knoten *o2,PRI pri,
struct Knoten *k,struct Knoten *p,int von)
{
struct Knoten *n,tmp;
OP op;
tmp.konst=1.;
if(pri==PRI_ADDSUB) {
n=o1->rechts;
if(n->pri!=PRI_MULDIV) {
n=NeuerK(OP_MUL);
n->links=Neuer_Operator(OP_MUL);
n->links->rechts=o1->rechts;
o1->rechts=n;
}
op=o2->op;
if(von==2) op=op==OP_ADD?OP_SUB:OP_ADD;
if(o2->rechts->pri==PRI_MULDIV)
Rechne(n,op,o2->rechts);
else Rechne(n,op,&tmp);
Baum_abbauen(o2);
if(p) p->links=o1->links;
else if(von==1) k->links=o1->links;
else k->rechts=o1->links;
o1->links=NULL;
if(von==2) o1->op=OP_SUB;
}
else if(pri==PRI_MULDIV) {
if(o1->rechts->op!=OP_POT || o1->rechts->rechts->flags.is.Konst==0
|| o1->rechts->rechts->op!=OP_NONE) {
n=Neuer_Operator(OP_POT);
n->rechts=Neue_Konst(1.);
n->links=o1->rechts;
o1->rechts=n;
}
else n=o1->rechts;
op=o2->op==OP_MUL?OP_ADD:OP_SUB;
if(von==2) op=op==OP_ADD?OP_SUB:OP_ADD;
if(o2->rechts->op==OP_POT && o2->rechts->rechts->flags.is.Konst &&
o2->rechts->rechts->op==OP_NONE)
Rechne(n->rechts,op,o2->rechts->rechts);
else Rechne(n->rechts,op,&tmp);
Baum_abbauen(o2);
if(p) p->links=o1->links;
else if(von==1) k->links=o1->links;
else k->rechts=o1->links;
o1->links=NULL;
if(von==2) o1->op=OP_DIV;
}
o1->rechts=Sinnlos(o1->rechts);
if(o1->rechts->op==OP_NONE && o1->rechts->flags.is.Konst)
if(pri==PRI_ADDSUB && o1->rechts->konst==0 ||
pri==PRI_MULDIV && o1->rechts->konst==1.) {
Baum_abbauen(o1);
o1=NULL;
}
k=Verschmelze(k,o1);
return Sinnlos(k);
}
BOOL dop_klammer(char **sp)
{
return (*sp!=Beginn && (*sp)[-1]!='(')?((*sp)++[0]='(',TRUE):FALSE;
}
BOOL pri_klammer(struct Knoten *v,struct Knoten *s,char **sp)
{
return (v->pri>s->pri && s->pri!=PRI_NONE || (v->pri==s->pri || s->pri==PRI_FUNC) && v->pri==PRI_POT || v->op==OP_USERF)?\
((*sp)++[0]='(',TRUE):FALSE;
}
void klammer_zu(char **sp,BOOL kl)
{
if(kl) (*sp)++[0]=')';
}
char *cut(char *s)
{
char *cp=s;
do;while(*--cp=='0');
if(isdigit(*cp)) s=cp+1;
else if(*cp=='.') s=cp;
*s=0; return s;
}
char *Baum_zu_String(struct Knoten *k,char *s)
{
if(k) s=Baum_String(k,Beginn=s);
else *s++='0';
*s=0; return s;
}
char *Baum_String(struct Knoten *k,char *s)
{
int i;
if(k->op==OP_NONE) {
if(k->flags.is.Konst) {
sprintf(s,"%lf",k->konst);
s=cut(strchr(s,0));
}
else if(k->flags.is.Neg) {
BOOL kl=dop_klammer(&s);
*s++='-';
strncpy(s,k->term,k->len); s+=k->len;
klammer_zu(&s,kl);
}
else {
strncpy(s,k->term,k->len); s+=k->len;
}
return s;
}
if(k->op>=OP_FUNC1) {
BOOL kl1,kl2;
if(k->flags.is.Neg) {
kl1=dop_klammer(&s);
*s++='-';
}
strncpy(s,k->term,k->len);
s+=k->len;
for(i=0;i<k->primes;i++) *s++='\'';
kl2=pri_klammer(k,k->rechts,&s);
if(!kl2) *s++=' ';
s=Baum_String(k->rechts,s);
klammer_zu(&s,kl2);
if(k->flags.is.Neg) klammer_zu(&s,kl1);
return s;
}
if(k->op==OP_POT) {
BOOL kl1,kl2;
if(k->flags.is.Neg) {
kl1=dop_klammer(&s);
*s++='-';
}
kl2=pri_klammer(k,k->links,&s);
s=Baum_String(k->links,s);
klammer_zu(&s,kl2);
*s++='^';
kl2=pri_klammer(k,k->rechts,&s);
s=Baum_String(k->rechts,s);
klammer_zu(&s,kl2);
if(k->flags.is.Neg) klammer_zu(&s,kl1);
return s;
}
if(k->flags.is.K) {
BOOL noop=FALSE,kl1,kl2;
struct Knoten *n;
if(k->flags.is.Konst && k->konst!=StdKonst(k->pri)) {
if(k->konst<0.) kl1=dop_klammer(&s);
sprintf(s,"%lf",k->konst);
s=cut(strchr(s,0));
if(k->konst<0.) klammer_zu(&s,kl1);
}
else if(k->links==NULL) {
if(k->pri==PRI_MULDIV) *s++='1';
}
else noop=TRUE;
n=k->links;
while(n) {
if(!noop) *s++=*Op(n->op);
else noop=FALSE;
kl2=pri_klammer(n,n->rechts,&s);
s=Baum_String(n->rechts,s);
klammer_zu(&s,kl2);
n=n->links;
}
n=k->rechts;
if(n) {
*s++=*Op(k->op);
noop=TRUE;
if(n->links) *s++='(';
while(n) {
if(!noop) *s++=*Op(n->op);
else noop=FALSE;
kl2=pri_klammer(n,n->rechts,&s);
s=Baum_String(n->rechts,s);
klammer_zu(&s,kl2);
n=n->links;
}
if(k->rechts->links) *s++=')';
}
}
return s;
}
#define WIDTH 60
struct node {
struct node *prev,*next;
char s[WIDTH+1];
};
struct list {
struct node *first,*last;
};
struct Knoten *u,*v,*a,*b,*K,*D;
char s1[20],s2[20],*muster,
*dMul[3]={"*ub","*va","+*av*bu"},
*dDiv[3]={"/_*ub^v2","/av","/-*av*bu^v2"},
*dPot[3]={"*^uv*#01ub","*v*^u-v1a","*^uv+*b#01u*/vua"},
*dFunk[]={"/bv","*#03vb","*#02vb","*#05vb","*_#04vb",
"/b^#03v2","_/b^#02v2","/b^#05v2","_/b^#04v2","*/bv#10e",
"/b#15-1^v2","_/b#15-1^v2","/b+1^v2","_/b+1^v2","/b*2#15v",
"/b#15+1^v2","/b#15-^v21","/b-1^v2","/b-1^v2","*b#20v"};
char *PotMsg1[3]={
"Bei &k ist die Basis &u konstant. Man verfährt wie folgt: "
"(c^v)'=ln c*c^v*v', mit c=&u und v=&v.",
"&k ist ein Term mit konstanter Potenz &v. Die Basis b ist &u. "
"Solche Terme differenziert man so: (b^c)'=c*b^(c-1)*b'.",
"Bei &k sind weder die Basis u=&u noch v=&v konstant. Man differenziert "
"Ausdrücke dieser Art folgendermaßen: (u^v)'=u^v*(v'*ln u+v*u'/u)."},
*PotMsg2[2]={"Differenzieren wir also einmal v.",
"Berechnen wir also die Ableitung der Basis b."},
*PotMsg3[3]={"Mit c=&u, v=&v und v'=&b wird &k nach (c^v)'=ln c*c^v*v' zu &d.",
"Damit wird &k nach (b^c)'=c*b^(c-1)*b' zu &d.",
"Mit u=&u, v=&v, u'=&a und v'=&b ergibt sich nach "
"(u^v)'=u^v*(v'*ln u+v*u'/u) aus &k das Ergebnis &d."},
*PotMsg4[2]={"v' ist dabei 1, &k wird also zu &d.",
"b' ist natürlich 1 und so erhalten wir &d."},
*ASMsg[3]={"Terme, die durch + oder - getrennt sind, werden einzeln "
"differenziert und anschließend wieder zusammengesetzt.",
"Die Konstante wird beim Differenzieren zu 0, wir müssen also"
" nur den Rest ableiten.","Da wir ja &k zu differenzieren"
" hatten, dürfen wir natürlich nicht auf das Minus vergessen"
" und erhalten deshalb &d."},
*MDMsg[5]={"Bei einer Division kommt die Quotientenregel "
"(u/v)'=(u'*v-v'*u)/v^2 zum Einsatz. Hier ist u= eine Konstante"
", die Ableitung u' also 0. Wir differenzieren also nach -v'*u"
"/v^2, mit v=&v.","Damit erhalten wir für &k nach -v'*c/v^2 mit v=&v"
" und v'=&b schlußendlich &d.","Der konstante Faktor bleibt"
" beim Differenzieren unverändert, wir differenzieren also erst"
" einmal den Rest.","Wir haben bei &k eine Division von u=&u durch"
" v=&v. Hier gilt die Quotientenregel (u/v)'=(u'*v-v'*u)/v^2.",
"Mit u=&u, v=&v, u'=&a und v'=&b wird &k nach der Quotientenregel"
" (u/v)'=(u'*v-v'*u)/v^2 zu &d."},
*MMsg[2]={"Bei einem Produkt zweier Terme u=&u und v=&v kommt"
" die Produktregel (u*v)'=u'*v+v'*u zum Einsatz.",
"Mit u=&u, v=&v, u'=&a und v'=&b ergibt sich nach (u*v)'="
"u'*v+v'*u aus &k eben &d."};
struct node *new_node(struct list *l)
{
struct node *n=malloc(sizeof(struct node));
if(n==NULL) {
fprintf(stderr,"Speicher voll!\n");
exit(10);
}
n->prev=n->next=NULL;
if(l->first) {
l->last->next=n;
n->prev=l->last;
l->last=n;
}
else l->first=l->last=n;
return n;
}
void behandle(char *src,char *dest)
{
char c;
while((c=*src++)!=0)
if(c!='&') *dest++=c;
else switch(*src++) {
case 'a': dest=Baum_zu_String(a,dest);break;
case 'b': dest=Baum_zu_String(b,dest);break;
case 'u': dest=Baum_zu_String(u,dest);break;
case 'v': dest=Baum_zu_String(v,dest);break;
case 'k': dest=Baum_zu_String(K,dest);break;
case 'd': dest=Baum_zu_String(D,dest);break;
case '1': strcpy(dest,s1);dest+=strlen(s1);break;
case '2': strcpy(dest,s2);dest+=strlen(s2);break;
case '#': sprintf(dest,"%lf",K->konst);
dest=cut(strchr(dest,0));break;
}
*dest=0;
}
void Schreibe(struct list *l,char *s)
{
static char um[]={" =+-*^/"};
struct node *n=new_node(l);
if(strlen(s)<=WIDTH) strcpy(n->s,s);
else {
int i=WIDTH+1;
while(--i>0) if(strchr(um,s[i])) break;
if(i<0) i=WIDTH;
else i++;
strncpy(n->s,s,i);
n->s[s[i-1]!=' '?i--:i-1]=0;
Schreibe(l,s+i);
}
}
void Ausgabe(struct list *l,char *s)
{
behandle(s,Puffer1); Schreibe(l,Puffer1);
}
void anhaengen(struct list *l,struct list *r)
{
if(!l->first) *l=*r;
else if(r->first) {
l->last->next=r->first;
r->first->prev=l->last;
l->last=r->last;
}
}
void Loesche(struct list *l)
{
struct node *n=l->first,*m;
while(n) {
m=n; n=n->next; free(m);
}
}
void beide_abl(struct list *l,struct list *r,struct list *li)
{
if(X(u)) {
Ausgabe(li,"Da u=x, ist u'=1. Berechnen wir also die Ableitung von v=&v.");
Loesche(l);
anhaengen(li,r);
}
else if(X(v)) {
Ausgabe(li,"Da v=x, ist v'=1. Berechnen wir also die Ableitung von u=&u.");
Loesche(r);
anhaengen(li,l);
}
else {
Ausgabe(li,"Berechnen wir zuerst einmal u'.");
anhaengen(li,l);
Ausgabe(li,"Für &k brauchen wir noch die Ableitung von v=&v.");
anhaengen(li,r);
}
}
Art(void)
{
int art=2;
if(!a || a->op==OP_NONE && a->flags.is.Konst && a->konst==0.) {
Baum_abbauen(a); a=NULL;
art-=2;
}
if(!b || b->op==OP_NONE && b->flags.is.Konst && b->konst==0.) {
Baum_abbauen(b); b=NULL;
art--;
}
return art;
}
struct Knoten *diffAdd(struct Knoten *k,struct list *li)
{
struct Knoten *l,*r;
if(k) {
r=Differenziere(k->rechts,li);
l=diffAdd(k->links,li);
if(l) r=Verkette(l,OP_ADD,r);
return r;
}
return NULL;
}
struct Knoten *diffMul(struct Knoten *k,struct list *li)
{
struct Knoten *l,*r;
int art;
struct list ll,rl;
if(k) {
ll.first=rl.first=NULL;
r=Differenziere(k->rechts,&ll);
l=diffMul(k->links,&rl);
if(!l) {
anhaengen(li,&ll);Loesche(&rl);
return r;
}
v=NeuerK(OP_MUL);
v->links=BaumKopie(k->links);
v=Sinnlos(v);
u=k->rechts;
b=l; a=r; art=Art();
if(art<0) return Neue_Konst(0.);
muster=dMul[art];
D=l=Sinnlos(Regeln());
K=NeuerK(OP_MUL);
K->links=k;
Ausgabe(li,MMsg[0]);
beide_abl(&ll,&rl,li);
Ausgabe(li,MMsg[1]);
K->links=NULL;
Baum_abbauen(K); Baum_abbauen(v);
Baum_abbauen(a); Baum_abbauen(b);
return l;
}
return NULL;
}
struct Knoten *Regeln(void)
{
struct Knoten *k;
int d;
switch(d=*muster++) {
case 'a': k=BaumKopie(a);break;
case 'b': k=BaumKopie(b);break;
case 'u': k=BaumKopie(u);break;
case 'v': k=BaumKopie(v);break;
case '_': Negiere(k=Regeln());break;
case 'e': k=Neues_Blatt("e",&cp);break;
case '#':
sscanf(muster,"%d",&d);
muster+=2;
k=Neuer_Operator(d+OP_FUNC1-1);
if(d==10) {k->term=K->term;k->len=K->len;}
k->rechts=Regeln();
break;
default:
if(isdigit(d)) k=Neue_Konst((double)(d-'0'));
else {
k=Regeln();
k=Verkette(k,opnr(d),Regeln());
}
}
return k;
}
struct Knoten *Differenziere(struct Knoten *k,struct list *li)
{
struct Knoten *d;
int art;
struct list ll,rl;
ll.first=rl.first=NULL; K=k;
if(k->op==OP_NONE) {
if(k->flags.is.Konst==0 && k->len==1 && *k->term=='x') {
Ausgabe(li,"x abgeleitet ergibt 1.");
return Neue_Konst(k->flags.is.Neg?-1.:1.);
}
Ausgabe(li,"Die Konstante &k abgeleitet ergibt 0.");
return Neue_Konst(0.);
}
if(k->op>=OP_FUNC1) {
if(C(k->rechts)) {
Ausgabe(li,"&k ist konstant, die Ableitung davon also 0.");
Loesche(&rl);
return Neue_Konst(0.);
}
b=Differenziere(k->rechts,&rl);
v=k->rechts;
if(k->op>=OP_USERF) {
u=BaumKopie(k);
u->primes++; muster="*ub";
}
else muster=dFunk[k->op-OP_FUNC1];
K=k; d=Regeln();
if(k->op>=OP_USERF) Baum_abbauen(u);
if(k->flags.is.Neg) Negiere(d);
d=D=Sinnlos(d); K=k;
strncpy(s1,k->term,k->len);
strcpy(s1+k->len," z");
if(!X(v)) {
if(k->op>=OP_USERF) Ausgabe(li,"Leiten wir die Funktion &k ab und multiplizieren wir sie mit der inneren Ableitung z'. Das Argument z ist &v.");
else {
strcpy(s2,FunkMsg[k->op-OP_FUNC1]);
Ausgabe(li,"Allgemein wird eine Funktion &1 beim Differenzieren zu &2. Hier ist z=&v.");
}
Ausgabe(li,"Berechnen wir die Ableitung davon.");
anhaengen(li,&rl);
if(k->op>=OP_USERF) Ausgabe(li,"Die Ableitung von &k ist also &d.");
else Ausgabe(li,"Wir bekommen also aus &1=&k nach der Vorschrift (&1)'=&2 als Ergebnis &d.");
}
else {
Ausgabe(li,"Die Funktion &k abgeleitet wird zu &d.");
Loesche(&rl);
}
Baum_abbauen(b);
return d;
}
if(k->op==OP_POT) {
d=Differenziere(k->links,&ll);
b=Differenziere(k->rechts,&rl);
a=d;
u=BaumKopie(k->links);
v=BaumKopie(k->rechts);
if((art=Art())<0) {
Ausgabe(li,"&k ist konstant, die Ableitung also 0.");
Loesche(&ll);Loesche(&rl);
return Neue_Konst(0.);
}
muster=dPot[art];
d=Regeln();
if(k->flags.is.Neg) Negiere(d);
D=d=Sinnlos(d); K=k;
Ausgabe(li,PotMsg1[art]);
if(art<2) {
if(!X(u) && !X(v)) {
Ausgabe(li,PotMsg2[art]);
anhaengen(li,art?&ll:&rl);
Ausgabe(li,PotMsg3[art]);
Loesche(art?&rl:&ll);
}
else {
Loesche(&ll);Loesche(&rl);
Ausgabe(li,PotMsg4[art]);
}
}
else {
if(X(u) && X(v)) {
Ausgabe(li,"Da u und v=x, sind sowohl u' als auch v'=1.");
Loesche(&ll); Loesche(&rl);
}
else beide_abl(&ll,&rl,li);
Ausgabe(li,PotMsg3[2]);
}
Baum_abbauen(u); Baum_abbauen(v);
Baum_abbauen(a); Baum_abbauen(b);
return d;
}
if(k->pri==PRI_ADDSUB) {
struct Knoten *l,*r;
BOOL einfach=k->links && !k->rechts && !k->links->links ||
k->rechts && !k->links && !k->rechts->links;
if(!einfach) Ausgabe(li,ASMsg[0]);
if(k->flags.is.Konst && k->konst!=0.) Ausgabe(li,ASMsg[1]);
l=diffAdd(k->links,li);
r=diffAdd(k->rechts,li);
if(!l) Negiere(d=r);
else if(!r) d=l;
else d=Verkette(l,OP_SUB,r);
D=d=Sinnlos(d); K=k;
if(!einfach)
Ausgabe(li,"&k differenziert ergibt also &d.");
else if(!k->links) Ausgabe(li,ASMsg[2]);
return d;
}
d=diffMul(k->links,&ll);
if(k->rechts) {
b=diffMul(k->rechts,&rl); a=d;
u=NeuerK(OP_MUL);
if(!k->links) u->konst=k->konst;
else u->links=BaumKopie(k->links);
u=Sinnlos(u);
v=NeuerK(OP_MUL);
v->links=BaumKopie(k->rechts);
v=Sinnlos(v);
if((art=Art())<0) return Neue_Konst(0.);
muster=dDiv[art];
d=Regeln();
}
if(k->links && k->flags.is.Konst && k->konst!=1.)
d=Verkette(d,OP_MUL,Neue_Konst(k->konst));
d=D=Sinnlos(d);
K=k;
if(!k->links) {
Ausgabe(li,MDMsg[0]);
if(!X(v)) {
Ausgabe(li,"Wir berechnen also einmal die Ableitung von &v.");
anhaengen(li,&rl);
Ausgabe(li,MDMsg[1]);
}
else {
Ausgabe(li,"v' ist natürlich 1 und wir erhalten &d.");
Loesche(&rl);
}
}
else {
BOOL ko=k->flags.is.Konst && k->konst!=1.;
if(ko) Ausgabe(li,MDMsg[2]);
if(k->rechts) {
Ausgabe(li,MDMsg[3]);
beide_abl(&ll,&rl,li);
Ausgabe(li,MDMsg[4]);
if(ko) Ausgabe(li,"Dabei wurde noch mit der Konstanten multipliziert.");
}
else {
anhaengen(li,&ll);
if(ko) Ausgabe(li,"Als Ergebnis von &k erhalten wir also &d.");
}
}
if(k->rechts) {
Baum_abbauen(u); Baum_abbauen(v);
Baum_abbauen(a); Baum_abbauen(b);
}
return d;
}
void diff(char *formel,struct list *l)
{
errno=0;
if(Term_korrekt(formel) && (K=Root=Baum_aufbauen(formel)) && errno==0) {
Ausgabe(l,"Angabe: &k");
D=Differenziere(Root,l);
Ausgabe(l,"Endergebnis: &d");
Baum_abbauen(D);
Baum_abbauen(Root);
}
else Ausgabe(l,"Angabe fehlerhaft!");
}
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Window *w;
struct RastPort *rp;
UBYTE Formel[256],AlteFormel[256],Kopie[256];
struct StringInfo si_Eingabe={Formel,AlteFormel,0,256};
struct Gadget gg_Eingabe={
NULL,20,25,520,11,GADGHCOMP,RELVERIFY,
STRGADGET,NULL,NULL,NULL,0,(APTR)&si_Eingabe,1,NULL};
struct NewWindow nw={
10,10,560,160,0,1,
GADGETUP|CLOSEWINDOW|RAWKEY,
WINDOWDRAG|WINDOWCLOSE|WINDOWDEPTH|ACTIVATE,&gg_Eingabe,
NULL,(UBYTE *)"How-To-Derive ... 1992 by Markus Öllinger (c) by M&T",
NULL,NULL,0,0,0,0,WBENCHSCREEN};
void Male(long x,long y,int w,char *t)
{
SetDrMd(rp,JAM1);
x=x+(w>>1)-(strlen(t)<<2);
SetAPen(rp,2);Move(rp,x+1,y+7);
Text(rp,t,(long)strlen(t));
SetAPen(rp,1);Move(rp,x,y+6);
Text(rp,t,(long)strlen(t));
}
void ende(int err)
{
if(w) CloseWindow(w);
if(GfxBase) CloseLibrary((struct Library *)GfxBase);
if(IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
}
void init(void)
{
atexit(ende);
if(!(IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",33)))
exit(1);
if(!(GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",33)))
exit(1);
if(!(w=OpenWindow(&nw))) exit(2);
rp=w->RPort;
SetRast(rp,3); RefreshWindowFrame(w);
SetAPen(rp,0); RectFill(rp,20,50,540,145);
ActivateGadget(&gg_Eingabe,w,NULL);
Male(0,15,560,"Angabe f(x)=?");
Male(0,40,560,"Lösungsweg");
}
void Zeige(struct node *n,long scroll,int s,int e)
{
int i;
SetAPen(rp,1); SetBPen(rp,0);
if(scroll) ScrollRaster(rp,0,scroll,20,50,540,145);
for(i=0;n && i<e;n=n->next,i++) if(i>=s) {
Move(rp,20,(long)(56+(i<<3)));
Text(rp,n->s,(long)strlen(n->s));
}
}
void main(int argc,char **argv)
{
struct IntuiMessage *msg;
ULONG class; USHORT code;
struct list l;
struct node *show=l.first=NULL;
init();
do {
WaitPort(w->UserPort);
msg=(struct IntuiMessage *)GetMsg(w->UserPort);
class=msg->Class; code=msg->Code;
ReplyMsg((struct Message *)msg);
if(class==GADGETUP) {
Loesche(&l); l.first=NULL;
diff(strcpy(Kopie,Formel),&l);
SetAPen(rp,0); RectFill(rp,20,50,540,145);
Zeige(show=l.first,0,0,12);
}
else if(class==RAWKEY) {
if(code==0x4c && show->prev) Zeige(show=show->prev,-8,0,1);
else if(code==0x4d && show->next) Zeige(show=show->next,8,11,12);
else if(code==0x45) break;
else if(code==0x44) ActivateGadget(&gg_Eingabe,w,NULL);
}
} while(class!=CLOSEWINDOW);
Loesche(&l);
exit(0);
}